/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/cat.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/

#include <windows.h>
#include <iostream>

#pragma warning(disable: 4091)
#include <Shlobj.h>
#pragma comment( lib, "Kernel32.lib" )
#pragma comment( lib, "Shell32.lib" )

// / -> \

int translate( char * lpszOut, int nBufLen, const char * lpszInput, int nMax )
{
    int ret = 0;

    int len = strnlen_s( lpszInput, nMax );

    if( ( 0 == ret ) && ( nBufLen - 1 < len ) )
    {
        ret = 1;
    }

    if( 0 == ret )
    {
        strcpy_s( lpszOut, nBufLen, lpszInput );
    }
    
    while( ( 0 == ret ) && *lpszOut )
    {
        if( ( *lpszOut ) == '/' )
        {
            *lpszOut = '\\';
        }
        lpszOut++;
    }
    
    return ret;
}

int mkdir( const char * lpszPath )
{
    int ret = 0;

    char temp[1024] = { 0 };
    char buf[1024] = { 0 };

    //printf( "path = %s\r\n", lpszPath );

    translate( temp, sizeof( temp ), lpszPath, 1024 );
    //printf( "trans = %s\r\n", temp );

    _fullpath( buf, temp, sizeof( buf ) );
    //printf( "real = %s\r\n", buf );

    BOOL bRet = SHCreateDirectoryExA( 0, buf, 0 );

    if( bRet )
    {
        return 0;
    }

    DWORD dwErr = GetLastError();
    ret = 1;

    switch( dwErr )
    {
    case ERROR_FILENAME_EXCED_RANGE:
        {
            printf( "path is too long : %s\r\n", lpszPath );
        }
        break;
    case ERROR_BAD_PATHNAME:
        {
            printf( "is relative path : %s\r\n", lpszPath );
        }
        break;
    case ERROR_PATH_NOT_FOUND:
        {
            printf( "invalid path : %s\r\n", lpszPath );
        }
        break;
    default:
        {
            ret = 0;
        }
        break;
    }

    return ret;
}

int del( const char * lpszFile )
{
    int ret = 0;

    char buf[1024] = { 0 };

    translate( buf, sizeof( buf ), lpszFile, 1024 );
    BOOL bRet = DeleteFileA( buf );

    if( bRet )
    {
        return 0;
    }

    DWORD dwErr = GetLastError();
    ret = 1;

    switch( dwErr )
    {
    case ERROR_FILE_NOT_FOUND:
        {
            printf( "file not found : %s\r\n", lpszFile );
        }
        break;
    case ERROR_ACCESS_DENIED:
        {
            printf( "file is readonly : %s\r\n", lpszFile );
        }
        break;
    default:
        {
            ret = 0;
        }
        break;
    }

    return ret;
}

// 
// make.exe xcp  /Y /S ..\config_files\* $(OutDir)webapps\www.cat.com_1111\
// 
int xcp( int argc, const char * argv[] )
{
    int ret = 0;

    char buf[4096] = "xcopy";
    char tr[1024];

    for( int i = 2; i < argc; ++i )
    {
        strcat_s( buf, " " );
        if( ( '/' == argv[i][0] ) && ( strlen( argv[i] ) < 4 ) )
        {
            strcat_s( buf, argv[i] );
        }
        else
        {
            translate( tr, sizeof( tr ), argv[i], 1024 );
            strcat_s( buf, tr );
        }
    }

    printf( "cmd : %s\r\n", buf );

    PROCESS_INFORMATION pi;
    STARTUPINFOA si;

    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );

    // Start the child process. 
    if( !CreateProcessA( 
        NULL,           // No module name (use command line)
        buf,            // Command line
        NULL,           // Process handle not inheritable
        NULL,           // Thread handle not inheritable
        FALSE,          // Set handle inheritance to FALSE
        0,              // No creation flags
        NULL,           // Use parent's environment block
        NULL,           // Use parent's starting directory 
        &si,            // Pointer to STARTUPINFO structure
        &pi )           // Pointer to PROCESS_INFORMATION structure
        ) 
    {
        printf( "CreateProcess failed (%d).\n", GetLastError() );
        return 1;
    }

    // Wait until child process exits.
    WaitForSingleObject( pi.hProcess, INFINITE );

    // Close process and thread handles. 
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );

    return ret;
}

int main( int argc, const char * argv[] )
{
    using namespace std;

    char buf[1024] = { 0 };
    int result = 1;
    int ret = 0;

    if( ( 0 == ret ) && ( argc < 3 ) )
    {
        ret = 1;
    }

    if( ( 0 == ret ) && ( argc == 4 ) &&  ( 0 == std::strcmp( argv[1], "copy" ) ) )
    {
        BOOL bRet = CopyFileA( argv[2], argv[3], false );
        if( !bRet )
        {
            printf( "copy file %s -> %s failed\r\n", argv[2], argv[3] );
        }
        result = 0;
        ret = 1;
    }

    if( ( 0 == ret ) && ( argc > 3 ) &&  ( 0 == std::strcmp( argv[1], "xcp" ) ) )
    {
        result = xcp( argc, argv );
        ret = 1;
    }

    // _fullpath
    if( ( 0 == ret ) && ( 3 == argc ) &&  ( 0 == std::strcmp( argv[1], "mkdir" ) ) )
    {
        result = mkdir( argv[2] );
        ret = 1;
    }

    if( ( 0 == ret ) && ( argc >= 3 ) && ( 0 == std::strcmp( argv[1], "del" ) ) )
    {
        for( int i = 2; i < argc; ++i )
        {
            del( argv[i] );
        }
        result = 0;
        ret = 1;
    }

    if( ( 1 == result ) || ( 0 == ret ) )
    {
        printf( "usage example : make.exe mkdir|del path(for mkdir)|file( for del file )\r\n" );
    }

    return result;
}
